package org.bes.WinClass;

import org.bes.api.IRollbacker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.json.*;
import javax.json.stream.JsonGenerator;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.bes.WinClass.FileManager.*;
import static org.bes.WinClass.VersionControl.compareVersion;

public class Rollbacker extends PatchInfo implements IRollbacker {
    public static Map<String, String> versionData;
    public static String backupVersion;
    private static final Logger log = LoggerFactory.getLogger(Rollbacker.class);

    // 版本回退功能
    public void rollbackToVersion(String targetVersion) {
        // 加载现有 JSON 文件
        JsonObject existingJson = null;
        Path versionFilePath = getPatchParentDir().resolve(VERSION_FILE);  // 确定文件路径
        if (Files.exists(versionFilePath)) {
            try (InputStream inputStream = Files.newInputStream(versionFilePath);
                 JsonReader reader = Json.createReader(inputStream)) {
                existingJson = reader.readObject();
            } catch (IOException e) {
                log.error("Error reading existing JSON file: " + e.getMessage());
            }
        }

        if (existingJson == null) {
            log.error("No existing JSON file found for rollback.");
            return;
        }

        // 加载现有的 common_files 和 jar_files
        JsonArray existingCommonFiles = existingJson.getJsonArray("common_files");
        JsonArray existingJarFiles = existingJson.getJsonArray("jar_files");

        // 将现有数据存入 map 方便修改
        Map<String, JsonObjectBuilder> commonFileMap = new HashMap<>();
        Map<String, JsonObjectBuilder> jarFileMap = new HashMap<>();

        // 处理现有 common files
        for (JsonObject commonFile : existingCommonFiles.getValuesAs(JsonObject.class)) {
            String filePath = commonFile.getString("common_file");
            commonFileMap.put(filePath, Json.createObjectBuilder(commonFile));
        }

        // 处理现有 jar files
        for (JsonObject jarFile : existingJarFiles.getValuesAs(JsonObject.class)) {
            String filePath = jarFile.getString("jar_file");
            jarFileMap.put(filePath, Json.createObjectBuilder(jarFile));
        }

        // 回退操作
        // 对于 common files
        List<String> keysToRemove = new ArrayList<>();
        for (Map.Entry<String, JsonObjectBuilder> entry : commonFileMap.entrySet()) {
            JsonObjectBuilder commonFileObjectBuilder = entry.getValue();
            JsonObject commonFileJson = commonFileObjectBuilder.build();
            String latestVersion = commonFileJson.getString("latest_version");
            commonFileObjectBuilder.add("common_file", commonFileJson.getString("common_file")); // 保留原始文件名

            // 进行版本回退操作，判断最新版本是否大于目标版本
            if (compareVersion(latestVersion, targetVersion) > 0) {

                // 回退操作 - 根据 operations 数组中的操作来回退
                JsonArray operations = commonFileJson.getJsonArray("operations");
                JsonArrayBuilder updatedOperations = Json.createArrayBuilder();

                // 保存 operations 中最大的小于等于目标版本的操作
                String maxOperationVersion = null;  // 用来记录最大的操作版本
                for (JsonObject operation : operations.getValuesAs(JsonObject.class)) {
                    String operationVersion = operation.getString("version");
                    if (compareVersion(operationVersion, targetVersion) <= 0) {
                        updatedOperations.add(operation); // 保留小于等于目标版本的操作
                        // 更新最大版本
                        if (maxOperationVersion == null || compareVersion(operationVersion, maxOperationVersion) > 0) {
                            maxOperationVersion = operationVersion;
                        }
                    }
                }

                JsonArray updatedOperationsArray = updatedOperations.build();

                // 如果没有可用的操作，删除该 common file
                if (updatedOperationsArray.isEmpty()) {
                    keysToRemove.add(entry.getKey()); // 标记该文件需要删除
                } else {
                    // 如果有操作，更新 latest_version 为最大操作版本
                    commonFileObjectBuilder.add("latest_version", maxOperationVersion);  // 更新为最大版本
                    commonFileObjectBuilder.add("operations", updatedOperationsArray);
                }
            } else {
                // 如果没有回退操作，保持原来的 latest_version
                commonFileObjectBuilder.add("latest_version", commonFileJson.getString("latest_version"));
                commonFileObjectBuilder.add("operations", commonFileJson.getJsonArray("operations"));
            }
        }


        // 删除标记为删除的文件
        for (String key : keysToRemove) {
            commonFileMap.remove(key);
        }

        // 对于 jar files

        for (Map.Entry<String, JsonObjectBuilder> entry : jarFileMap.entrySet()) {
            JsonObjectBuilder jarFileObjectBuilder = entry.getValue();
            JsonObject jarFileJson = jarFileObjectBuilder.build();
            String latestVersion = jarFileJson.getString("latest_operation_version");
            jarFileObjectBuilder.add("jar_file", jarFileJson.getString("jar_file")); // 保留原始文件名

            if (compareVersion(latestVersion, targetVersion) > 0) {
                // 回退操作 - 根据 files 中的每个 file 来回退
                JsonArray filesArray = jarFileJson.getJsonArray("files");
                JsonArrayBuilder updatedFiles = Json.createArrayBuilder();

                for (JsonObject fileObject : filesArray.getValuesAs(JsonObject.class)) {
                    String filePath = fileObject.getString("file");
                    JsonArray operations = fileObject.getJsonArray("operations");

                    // 如果 operations 为空，则跳过该 fileObject
                    if (operations.isEmpty()) {
                        continue;
                    }

                    JsonArrayBuilder updatedOperations = Json.createArrayBuilder();
                    String maxVersion = null; // 用来记录最大的操作版本

                    for (JsonObject operation : operations.getValuesAs(JsonObject.class)) {
                        String operationVersion = operation.getString("version");
                        if (compareVersion(operationVersion, targetVersion) > 0) {
                            // 删除操作版本大于目标版本的操作
                            continue;
                        }
                        updatedOperations.add(operation); // 保留小于等于目标版本的操作

                        // 更新最大版本
                        if (maxVersion == null || compareVersion(operationVersion, maxVersion) > 0) {
                            maxVersion = operationVersion;
                        }
                    }

                    // 如果 operations 被清空（没有小于等于目标版本的操作），则不添加该文件
                    JsonArray updatedOperationsArray = updatedOperations.build();
                    if (updatedOperationsArray.isEmpty()) {
                        continue;
                    }

                    // 更新 fileObject 中的 operations
                    JsonObjectBuilder updatedFileObject = Json.createObjectBuilder(fileObject)
                            .add("operations", updatedOperationsArray);

                    // 更新 latest_version 为 operations 中最大的版本
                    if (maxVersion != null) {
                        updatedFileObject.add("latest_version", maxVersion);
                    }

                    updatedFiles.add(updatedFileObject);
                }


                // 如果 files 数组为空，则删除整个 jar 文件
                JsonArray updatedFilesArray = updatedFiles.build();
                if (updatedFilesArray.isEmpty()) {
                    jarFileMap.remove(entry.getKey()); // 删除整个 jarFileObjectBuilder 内容
                } else {
                    jarFileObjectBuilder.add("latest_operation_version", targetVersion);  // 更新 jar 文件的版本
                    jarFileObjectBuilder.add("files", updatedFilesArray); // 更新 files 数组
                }

            } else {
                jarFileObjectBuilder.add("latest_operation_version", jarFileJson.getString("latest_operation_version"));  // 保留原始版本
                jarFileObjectBuilder.add("files", jarFileJson.getJsonArray("files"));  // 保留原始文件内容
            }
        }


        // 合并所有 common files 和 jar files
        JsonArrayBuilder commonFileArrayBuilder = Json.createArrayBuilder();
        for (JsonObjectBuilder builder : commonFileMap.values()) {
            commonFileArrayBuilder.add(builder);
        }

        JsonArrayBuilder jarFileArrayBuilder = Json.createArrayBuilder();
        for (JsonObjectBuilder builder : jarFileMap.values()) {
            jarFileArrayBuilder.add(builder);
        }

        // 将 common files 和 jar files 加入最终的 JSON
        JsonObjectBuilder allJsonObjectBuilder = Json.createObjectBuilder();
        allJsonObjectBuilder.add("common_files", commonFileArrayBuilder);
        allJsonObjectBuilder.add("jar_files", jarFileArrayBuilder);

        // 生成最终 JSON
        JsonObject finalJson = allJsonObjectBuilder.build();

        // 写回 JSON 文件
        try (FileWriter writer = new FileWriter(versionFilePath.toFile())) {
            JsonWriter jsonWriter = Json.createWriterFactory(
                    new java.util.HashMap<String, Boolean>() {{
                        put(JsonGenerator.PRETTY_PRINTING, true);
                    }}).createWriter(writer);
            jsonWriter.write(finalJson);
        } catch (IOException e) {
            log.error("Error writing JSON file after rollback: " + e.getMessage());
        }
    }





    //public void rollbackToVersion(String targetVersion) throws IOException {
    //    Path versionFilePath = FileManager.getPatchParentDir().resolve(FileManager.VERSION_FILE); // 获取 .version 文件路径
    //    Path backupDir = FileManager.getBackupDir();  // 获取备份文件夹路径
    //
    //    if (!Files.exists(versionFilePath)) {
    //        System.err.println(".version file not found!");
    //        return;
    //    }
    //
    //    Set<String> filesToRollback = versionData.entrySet().stream()
    //            .filter(entry -> isVersionGreater(entry.getValue(), targetVersion))  // 判断版本号是否大于目标版本号
    //            .map(Map.Entry::getKey) // 获取文件路径
    //            .collect(Collectors.toSet());
    //
    //
    //    if (filesToRollback.isEmpty()) {
    //        System.out.println("No files need to be rolled back.");
    //        return;
    //    }
    //
    //    // 3. 查找目标版本的备份文件夹
    //    Path targetBackupFolder = getBackupFolderForVersion(backupDir, targetVersion);
    //    if (targetBackupFolder == null) {
    //        System.err.println("No backup folder found for version " + targetVersion);
    //        return;
    //    }
    //
    //    // 4. 遍历需要回滚的文件，恢复它们
    //    for (String filePath : filesToRollback) {
    //        // 计算备份文件路径
    //        Path backupFilePath = targetBackupFolder.resolve(filePath);
    //        Path originalFilePath = FileManager.getSourceDir().resolve(filePath);
    //        FileDelete.deleteFile(originalFilePath.toFile());
    //
    //        if (Files.exists(backupFilePath)) {
    //
    //            // 确保目标目录存在
    //            Files.createDirectories(originalFilePath.getParent());
    //
    //            // 如果是 .jar 文件，调用 processJarFiles 进行处理
    //            if (filePath.endsWith(".jar")) {
    //                rollbackJarFile(filePath, backupFilePath, targetBackupFolder);
    //            } else {
    //                // 5. 拷贝文件到原位置
    //                Files.copy(backupFilePath, originalFilePath, StandardCopyOption.REPLACE_EXISTING);
    //                System.out.println("Rolled back file: " + filePath);
    //            }
    //
    //            // 6. 更新 .version 文件中该文件的版本号为备份的版本
    //            backupVersion = getBackupVersion(backupFilePath);
    //            versionData.put(filePath, backupVersion); // 更新版本号
    //        }
    //
    //    }
    //
    //    if (Files.exists(targetBackupFolder.resolve(JSON_DELETE))){
    //        UpdatePatch.jsonUpdate(targetBackupFolder.resolve(JSON_DELETE).toFile(), "rollback");
    //    }
    //
    //
    //    // 7. 写回更新后的版本信息
    //    //VersionControl.writeVersionInfo(versionData);
    //
    //    System.out.println("Rollback completed.");
    //}

    private void rollbackJarFile(String jarFilePath, Path backupFilePath, Path targetBackupFolder) throws IOException {
        String jarPath = jarFilePath.split("!")[0];
        String internalFilePath = jarFilePath.split("!")[1];

        Path originalJarPath = FileManager.getSourceDir().resolve(jarPath);
        if (!Files.exists(originalJarPath)) {
            System.err.println("JAR file missing: " + jarPath);
            return;
        }

        // 递归查找备份文件，按版本号回退
        Path finalBackupFilePath = findBackupForJarSubFile(jarFilePath, targetBackupFolder);
        if (finalBackupFilePath == null) {
            System.err.println("No valid backup found for JAR subfile: " + jarFilePath);
            return;
        }

        // 处理 JAR 文件内部的子文件回退
        processJarSubFile(finalBackupFilePath.toFile(), originalJarPath, internalFilePath);
        System.out.println("Rolled back JAR subfile: " + jarFilePath);

        // 更新 .version 文件
        String backupVersion = getBackupVersion(finalBackupFilePath);
        versionData.put(jarFilePath, backupVersion);
    }


    public static void processJarSubFile(File backupSubFile, Path originalJar, String subFilePath) throws IOException {
        File tempJar = new File(originalJar.toString() + ".tmp");

        try (JarFile jarFile = new JarFile(originalJar.toFile());
             JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(tempJar))) {

            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                InputStream is = jarFile.getInputStream(entry);

                // 如果是要回滚的子文件，则用备份替换
                if (entry.getName().equals(subFilePath)) {
                    jarOut.putNextEntry(new JarEntry(subFilePath));
                    Files.copy(backupSubFile.toPath(), jarOut);
                } else {
                    jarOut.putNextEntry(new JarEntry(entry.getName()));
                    is.transferTo(jarOut);
                }
                jarOut.closeEntry();
            }
        }

        // 替换原 JAR 文件
        Files.move(tempJar.toPath(), originalJar, StandardCopyOption.REPLACE_EXISTING);
    }

    private Path findBackupForJarSubFile(String jarFilePath, Path targetBackupFolder) throws IOException {
        String jarPath = jarFilePath.split("!")[0];
        String internalFilePath = jarFilePath.split("!")[1];

        // 查找所有补丁文件夹（按版本顺序查找）
        List<Path> sortedBackupFolders = getSortedBackupFolders(targetBackupFolder);

        for (Path backupFolder : sortedBackupFolders) {
            Path backupFile = backupFolder.resolve(jarFilePath);

            if (Files.exists(backupFile)) {
                return backupFile; // 找到最接近的备份文件
            }
        }

        return null; // 没有找到备份
    }

    private List<Path> getSortedBackupFolders(Path targetBackupFolder) throws IOException {
        try {
            return Files.list(targetBackupFolder)
                    .filter(Files::isDirectory)
                    .sorted(Comparator.comparing(Path::getFileName)) // 按版本号排序
                    .collect(Collectors.toList());
        } catch (IOException e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

    // 从备份文件路径获取文件的版本号（假设每个备份文件路径中都有版本号信息）
    private String getBackupVersion(Path backupFilePath) {
        // 提取文件路径中的版本号
        Matcher matcher = Pattern.compile("V(\\d+\\.\\d+\\.\\d+)").matcher(backupFilePath.toString());
        if (matcher.find()) {
            return matcher.group(1); // 返回版本号部分
        }
        return null;
    }

    // 获取目标版本对应的备份文件夹
    private Path getBackupFolderForVersion(Path backupDir, String targetVersion) throws IOException {
        // 遍历备份目录，查找对应版本的文件夹（例如 apache-patch-V1.1.0）
        try (Stream<Path> paths = Files.walk(backupDir)) {
            return paths.filter(Files::isDirectory)  // 只考虑文件夹
                    .filter(path -> path.getFileName().toString().equals("apache-patch-V" + targetVersion))  // 匹配目标版本
                    .findFirst()
                    .orElse(null);  // 如果没有找到，返回 null
        }
    }

    // 判断版本号是否大于目标版本号
    private boolean isVersionGreater(String version1, String targetVersion) {
        return compareVersions(version1, targetVersion) > 0;
    }

    // 比较版本号
    private int compareVersions(String version1, String version2) {
        String[] parts1 = version1.split("\\.");
        String[] parts2 = version2.split("\\.");

        int length = Math.min(parts1.length, parts2.length);

        for (int i = 0; i < length; i++) {
            int part1 = Integer.parseInt(parts1[i]);
            int part2 = Integer.parseInt(parts2[i]);
            if (part1 != part2) {
                return part1 - part2;
            }
        }

        return parts1.length - parts2.length; // 如果前面部分相同，比较长度
    }

    @Override
    public void rollback() {

        Path tmpDir = FileManager.getTmpDir();
        Path rootDir = FileManager.getSourceDir();
        if (!Files.exists(tmpDir)) {
            System.out.println("Tmp folder does not exist, unable to rollback patches.");
            return;
        }

        try {
            // Traverse all files and directories in the tmp folder
            Files.walk(tmpDir)
                    .filter(Files::isRegularFile) // Process only files
                    .forEach(tmpFilePath -> {
                        try {
                            // Calculate target path: root directory + relative path
                            Path relativePath = tmpDir.relativize(tmpFilePath);
                            Path targetPath = rootDir.resolve(relativePath);

                            // Ensure the target folder exists
                            if (!Files.exists(targetPath.getParent())) {
                                Files.createDirectories(targetPath.getParent());
                            }

                            // Copy file to the target path
                            Files.copy(tmpFilePath, targetPath, StandardCopyOption.REPLACE_EXISTING);

                            // Get patch version information
                            String fileVersion = new PatchInfo().getPatchInfo(tmpFilePath.toFile()).getPatchVersion();
                            if (fileVersion != null) {
                                System.out.println("Successfully rolled back file " + tmpFilePath.getFileName() + ", Patch version: " + fileVersion);
                            } else {
                                System.out.println("Successfully rolled back file " + tmpFilePath.getFileName());
                            }

                        } catch (IOException e) {
                            System.err.println("Failed to rollback file " + tmpFilePath.getFileName() + ": " + e.getMessage());
                        }
                    });
        } catch (IOException e) {
            System.err.println("Error traversing the tmp folder: " + e.getMessage());
        }
    }

    public void confirmBack() {
        System.out.println("Rollback operation completed. Press any key to exit.");
        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
        System.exit(0);
    }


    private boolean isFileMarkedForDeletion(String filePath, Path toDeleteJsonPath) throws IOException {


        if (!Files.exists(toDeleteJsonPath)) {
            return false;  // 如果 ToDelete.json 文件不存在，则返回 false
        }

        try (InputStream inputStream = Files.newInputStream(toDeleteJsonPath);
             JsonReader jsonReader = Json.createReader(inputStream)) {

            JsonObject jsonObject = jsonReader.readObject();
            JsonArray deleteFilesArray = jsonObject.getJsonArray("delete_files");

            // 遍历 "delete_files" 数组，检查文件是否在其中
            for (JsonValue value : deleteFilesArray) {
                if (value.getValueType() == JsonValue.ValueType.STRING) {
                    // 直接匹配字符串文件路径
                    if (value.toString().replace("\"", "").equals(filePath)) {
                        return true;
                    }
                } else if (value.getValueType() == JsonValue.ValueType.OBJECT) {
                    // 处理包含 JAR 文件和类文件的对象
                    JsonObject fileObject = (JsonObject) value;
                    String jarFilePath = fileObject.getString("jar_file");
                    JsonArray deleteClasses = fileObject.getJsonArray("delete_classes");

                    // 检查 JAR 文件和类是否匹配
                    if (filePath.equals(jarFilePath)) {
                        for (JsonValue classToDelete : deleteClasses) {
                            if (classToDelete.toString().replace("\"", "").equals(filePath)) {
                                return true;  // 如果该文件存在于 delete_classes 中，标记为删除
                            }
                        }
                    }
                }
            }
        }

        return false;  // 如果没有找到匹配的删除文件，则返回 false
    }

}
